################# settings to adjust from here or bashrc  ##############

msCXX ?= g++




ifdef USE_CC
# msCFLAGS += -MMD -MP
else
#ifdef USE_CPP17
 msCFLAGS += -std=c++17 -MMD -MP  -Wall
 msLFLAGS += -lstdc++fs
#else
# msCFLAGS += -std=c++11 -MMD -MP
endif

# msSrc=
# msRoot=
# msBinDir=

#FIXME: MPICPP = mpic++

############# set via makefile of individual applications ##############

# USE_TIFF=1
# USE_ZLIB=1
# USE_OMP=1


########################### Cross-compile ############################
ifeq "${OPT}" ".exe"
  preCC=x86_64-w64-mingw32-
  msCXX=${preCC}g++
  msLFLAGS += -static -static-libstdc++ -static-libgcc
  $(info msCXX=$(msCXX))
endif


########################################################################
#################### no need to change here after   ####################


#link relative path to exe
#msCFLAGS ?= -Wl,-rpath,'$ORIGIN/../lib' 

ifndef msSrc  # set msSrc to upper directory if not already set
 msSrc := $(abspath $(lastword $(MAKEFILE_LIST))/../..)
 $(info msSrc set to ${msSrc})
endif

msRoot ?= $(abspath ${msSrc}/..)

# set msBinDir if not set
msBinDir ?= ${msRoot}/bin
msLibDir ?= ${msRoot}/lib




# set thirdparty pkgs directory if not set
ifndef ms3rd
  ifneq ("$(wildcard ${msRoot}/pkgs/)","")
   ms3rd := ${msRoot}/pkgs
  else
   $(warning ms3rd not set ${ms3rd})
  endif
endif


ifneq ($(MAKECMDGOALS),clean) ############### if not cleaning  ###############:

msReleaseDate ?= \"$(shell date +'%Y.%m.%d')\"


msCFLAGS += -I${msSrc}/include -I${msRoot}/include -DRELEASE_DATE=$(msReleaseDate) -D_FILE_OFFSET_BITS=64
msLFLAGS += -L$(msLibDir)


InDir=In $(notdir $(abspath $(dir $(PWD))))/$(notdir $(PWD)): ***  


ifeq (${USE_VXIMG},1)
 ifdef USED_VXLIB
   $(info $(InDir) using voxlib instead of libvoxel)
 else 
   msCFLAGS += -I${msSrc}/libvoxel
 endif
endif


# set libtiff install directory: TIFDIR
ifdef USE_TIFF
 TIFDIR?=${msRoot}
 ifneq ("$(wildcard ${TIFDIR}/include/tiff.h)","")
   msCFLAGS += -I${TIFDIR}/include -DTIFLIB 
   msLFLAGS += -L${TIFDIR}/libtiff -ltiff -ltiffxx

   ifneq ($(shell ${msCXX} -ljpeg 2>&1 | grep ljpeg > /dev/null; echo $$?),0)
       msLFLAGS += -ljpeg 
   #else
     #$(info ignoring jpeg)
   endif

   ifneq ($(shell ${msCXX} -llzma 2>&1 | grep llzma > /dev/null; echo $$?),0)
      msLFLAGS += -llzma 
   endif

 else
   $(info $(InDir) tiff.h not found in ${TIFDIR}/include, nor in ${msRoot}/include/, ignoring USE_TIFF)
 endif
endif



# set zlib directory
# Note: ${ZLIBDIR}/contrib/iostream3/zfstream.h should be installed too
ifdef USE_ZLIB
 ZLIBDIR?=${msRoot}
 ifneq ("$(wildcard ${ZLIBDIR}/include/zlib.h)","")
   msCFLAGS += -I${ZLIBDIR}/include -DZLIB
   msLFLAGS += -L${ZLIBDIR}/lib -lz
 else
   $(info $(InDir) ZLIBDIR, ${ms3rd}/zlib/zlib.h, not found, ignoring USE_ZLIB)
 endif
endif



# set hypre directory, also gnflow multithreading
ifdef USE_HYPRE
 HYPREDIR=${msRoot}
 ifeq ("$(wildcard ${HYPREDIR}/include/HYPRE.h)","")
   HYPREDIR=${ms3rd}/hypre/src/hypre
 endif
 ifneq ("$(wildcard ${HYPREDIR}/include/HYPRE.h)","")
  msCFLAGS += -DHAVE_CONFIG_H -DHYPRE_TIMING -I${HYPREDIR}/include  -DMULTITHREAD
  msLFLAGS += -pthread  ${HYPREDIR}/lib/libHYPRE.a 
 else
   $(info $(InDir))
   $(error HYPREDIR, ${HYPREDIR}/include/HYPRE.h, not found)
 endif
endif



# set hypre directory, also gnflow multithreading -DMULTITHREAD
ifdef USE_HYPRESEQ
 HYPREDIR=${msRoot}
 ifeq ("$(wildcard ${HYPREDIR}/include/HYPRE.h)","")
   HYPREDIR=${ms3rd}/hypre/src/hypre
 endif
 ifneq ("$(wildcard ${HYPREDIR}/include/HYPRE.h)","")
  msCFLAGS += -DHAVE_CONFIG_H -DHYPRE_TIMING -I${HYPREDIR}/include
  msLFLAGS += -pthread  ${HYPREDIR}/lib/libHYPRESeq.a 
 else
   $(info $(InDir))
   $(error HYPREDIR, ${HYPREDIR}/include/HYPRE.h, not found)
 endif
endif




# svplot not released yet
ifdef USE_SVG
 ifneq ("$(wildcard ${ms3rd}/svplot/svplot.hpp)","")
   msCFLAGS += -I${ms3rd}/svplot -DSVG
 else
   $(info $(InDir) ignoring USE_SVG, ${ms3rd}/svplot/svplot.hpp, not found)
 endif
endif








ifneq "${OPT}" ".exe"
 # set openMP for parallel image processing, mesh generation ... 
 # not yet fully integrated with the "released" codes due to portability issues / being experimental 
 ifdef USE_OMP 
  msCFLAGS += -DOpenMP $(shell mpic++ -showme:compile) -fopenmp
  msLFLAGS += $(shell mpic++ -showme:link)  -fopenmp
 endif
else
 msLFLAGS += -static -lstdc++ -lm   -lstdc++fs
 ifdef USE_OMP 
  msCFLAGS += -DOpenMP -fopenmp
  msLFLAGS += -fopenmp
 endif
endif




ifeq ($(USE_XDMF),1)
   msCFLAGS += -I${msSrc}/Xdmf -DXDMF  
endif


endif                        ###############  if not cleaning  ###############:





ifeq "${OPT}" "dbg"
 msCFLAGS += -g -fno-inline  -D_debugCompile_  -D_extraCompile_ ${CFLAGSExtra} 
else
 msCFLAGS += -O3  ${CFLAGSExtra}
endif


# check and otherwise set default name for executable
makFilDir:=${CURDIR}
ifndef exec
 exec:=$(shell basename ${CURDIR})${OPT}
endif


# set build and test directories here, lib and bin are set through bashrc file
msBuildDir ?= ${msRoot}/build/${exec}
msTestDir ?= ${msRoot}/test/${exec}

psAppDirs:
	$(info  BuildDir: ${msBuildDir},   BinDir: $(msBinDir))
	@mkdir -p $(msBinDir)
	@mkdir -p ${msBuildDir}

msLibDirs:
	$(warning  BuildDir: ${msBuildDir},  LibDir: $(msLibDir))
	@mkdir -p $(msLibDir)
	@mkdir -p ${msBuildDir}

msTstDirs:
	@mkdir -p ${msTestDir}



ifdef USE_MINIFOAMX3  #######################################################:
  # TODO: these need furhter testing and clean up
  WM_PRECISION_OPTION ?= DP
  WM_ARCH ?= linux64
  GFLAGS = -DWM_LABEL_SIZE=32

 ifneq ("$(wildcard ${msRoot}/pkgs/foamx4m)","")
  WM_PROJECT_DIR ?= ${ms3rd}/foamx4m
  WM_PROJECT ?= foam
  WM_OSTYPE  ?= POSIX
  SO         ?= ext3.so
  # this could cause conflicts if openfoam is compiled differently:
  WM_MPLIB   ?= SYSTEMOPENMPI
  include $(WM_PROJECT_DIR)/wmake/rules/linux64Gcc/mplib$(WM_MPLIB)
  GFLAGS += -DFOAMX
  OFInsDIR=${msRoot}
 else
  $(info WM_PROJECT_DIR= $(WM_PROJECT_DIR))
  WM_PROJECT ?= OpenFOAM
  WM_PROJECT_DIR ?= /opt/openfoam9
  GFLAGS = -DWM_LABEL_SIZE=32
  SO  = so
  OFInsDIR=${WM_PROJECT_DIR}/platforms/${WM_ARCH}${WM_COMPILER}${WM_PRECISION_OPTION}Int${WM_LABEL_SIZE}Opt
  msLFLAGS += -L${OFInsDIR}/lib   
  msLFLAGS += -L${OFInsDIR}/lib/openmpi-system -Wl,-rpath=${OFInsDIR}/lib/openmpi-system -l:libPstream.$(SO)
 endif

  # $(info WM_PROJECT_DIR= $(WM_PROJECT_DIR))

  LIB_SRC            = $(WM_PROJECT_DIR)/src
  GFLAGS     += -D$(WM_ARCH) -DWM_$(WM_PRECISION_OPTION) 

  GFLAGS += -Wall -Wextra -Wno-unused-parameter -Wnon-virtual-dtor  -DNoRepository -ftemplate-depth-200
  #$(info GFLAGS: $(GFLAGS))

  msCFLAGS += $(PFLAGS) $(PINC) $(GFLAGS)
  #$(info  using of=$(OFInsDIR) msCFLAGS=$(msCFLAGS) )



  findOFsubdirs = $(shell find $(LIB_SRC)/$(dir) -type d ! -name 'lnInclude' -exec realpath --relative-to . {} \;)
  ofIncDirs = $(foreach dir,$(OFincs) $(WM_PROJECT) OSspecific/$(WM_OSTYPE),$(findOFsubdirs))
  OFCFLAGS += $(addprefix -I,$(ofIncDirs)) 
#  $(info $(ofIncDirs))
  
  msLFLAGS += $(PLIBS) -Wl,-rpath=${OFInsDIR}/lib  $(addprefix -l:lib,$(addsuffix .$(SO),$(OFlibs) $(WM_PROJECT)))   


  OFObj2C = $(subst ${msBuildDir}/,,$(subst __,/,$(subst ++,..,$(subst .Obj,.C,$@))))
  OFC2Obj = $(addprefix ${msBuildDir}/,$(subst /,__,$(subst ..,++,$(OFCs:.C=.Obj))))
  OFC2dep = $(addprefix ${msBuildDir}/,$(subst /,__,$(subst ..,++,$(OFCs:.C=.d))))
  
  objs += $(OFC2Obj)
  deps += $(OFC2dep)
else
  SO         ?= .so
endif  # USE_MINIFOAMX3  #######################################################:













#########################################################################
### defaults to be included in makefiles by setting USE_msMAKE=1
#########################################################################

#### WARNING: last make should be called from inside source folder  #####




ifdef   USE_msRecurse ############# run make in subfolders ###################:
makls=$(shell find */ -maxdepth 1 -type f | grep -e    /makefile$$     | grep -v [\ \(\)] | grep -v [-]/ | sed s/\\/makefile//g)
makes=$(shell find */ -maxdepth 1 -type f | grep -e    /Makefile$$     | grep -v [\ \(\)] | grep -v [-]/ | sed s/\\/Makefile//g)
# cmaks=$(shell find */ -maxdepth 1 -type f | grep -e /CMakeLists.txt$$  | grep -v [\ \(\)] | grep -v [-]/ | sed s/\\/CMakeLists.txt//g)

recurseMakeLibs: $(addprefix make_,${makls}) 

recurseMakeExes: $(addprefix make_,${makes}) 

recurseMake: 
	@$(MAKE) -f ${msSrc}/script/Makefile.in recurseMakeLibs USE_msRecurse=1
	@$(MAKE) -f ${msSrc}/script/Makefile.in recurseMakeExes USE_msRecurse=1
	@printf '\n*  ${makls}  ${makes}  :/ \n\n'

recurseClean: $(addprefix clean_,${makes})
	@printf '\n* $^ :/\n\n'

# msBilDir ?= $msRoot/build
# cm2xe = $(@:cmak_%=%)
# cmak_%:; @printf '\n$@: \n'
#	 (cd  $(cm2xe)  && $(MAKE)  USE_msRecurse='')
#	 mkdir -p ${msBilDir}/$(cm2xe) 
#	 cmake -S$(PWD)/$(cm2xe)   -B${msBilDir}/$(cm2xe)
#	 cmake --build ${msBilDir}/$(cm2xe) -j
#	 cmake --install  ${msBilDir}/$(cm2xe)

make_%:; @printf '\n$@: \n'
	@(cd  $(@:make_%=%)  && $(MAKE)  USE_msRecurse='')

clean_%:; @printf '\n$@: \n'
	@(cd  $(@:clean_%=%) && $(MAKE) clean  USE_msRecurse='' || echo '  check clean target for $(PWD)/$(@:clean_%=%)' )

else
  recurseMake:  ; $(error recurseMake  target requested without USE_msRecurse=1, $^)
  recurseClean: ; $(error recurseClean target requested without USE_msRecurse=1, $^)
endif  # USE_msRecurse  #####################################################:





ifdef   USE_SINGLECPP   ################ single-source .cpp app ##################:
 $(info  Single-source apps)
 cpp2d := $(addprefix ${msBuildDir}/,$(subst /,__,$(subst ..,++,$(srcs:.cpp=.d))))
 cpp2o = $(addprefix ${msBuildDir}/,$(subst /,__,$(subst ..,++,$(@:.cpp=.o))))
 cps2o := $(addprefix ${msBuildDir}/,$(subst /,__,$(subst ..,++,$(srcs:.cpp=.o))))
 o2cpp = $(subst ${msBuildDir}/,$(CURDIR)/,$(subst __,/,$(subst ++,..,$(subst .o,.cpp,$@))))

${msBuildDir}/%.o: $(o2cpp)
	@echo  'Compiling $(o2cpp) *'
	@${msCXX} ${msCFLAGS} -c $(o2cpp)   -o $@

$(srcs): psAppDirs $(cps2o) 
	@echo  Building  $(cpp2o) '>> ' $(@:.cpp=${OPT})
	@${msCXX} $(cpp2o)  -o $(msBinDir)/$(@:.cpp=)${OPT} ${msLFLAGS}

-include $(cpp2d)

.PHONY:  clean $(cpp2d)

clean:
	$(RM) $(cps2o) $(cpp2d)

endif #  USE_SINGLECPP    #####################################################:



# Warning: VTK-8.9 and upwards do not work on t3&4(Ubuntu16)
ifdef USE_VTK 
 msCmakeFLAGS += -DVTK_DIR:PATH=${HOME}/.local/lib/cmake/vtk-8.2  -DCMAKE_INSTALL_PREFIX=${msRoot} 
endif

ifdef USE_msCMAKE  ################## compile Cmake app/lib ##################:
msCApp:
	mkdir -p  ${msBuildDir}
	(cd       ${msBuildDir} &&  cmake $(msCmakeFLAGS) -DmsSrc=${msSrc} $(makFilDir))
	(cd       ${msBuildDir} &&  make VERBOSE=1) || echo ${exec} not built, continuing anyway
	@cp ${msBuildDir}/${exec} $(msBinDir)        || echo Warning:  cannot copy ${msBuildDir}/${exec}, but continuing
clean: ; cd ${msBuildDir} && make clean && rm -rf ${msBuildDir}
else
  msCApp: ; $(error msCApp target should be used togather with USE_msCMAKE=1, $^)
endif # USE_msCMAKE  ########################################################:





ifdef USE_msMAKE ################ compile single app folder ######################:
  # recursively include subfolders
  _rI = $(addprefix -I,$(shell find $(1) -type d)) 
  
  # convert .cpp file paths to .o, .d and vise versa
  o2cpp = $(subst ${msBuildDir}/,,$(subst __,/,$(subst ++,..,$(subst .o,.cpp,$@))))
  cpp2o = $(addprefix ${msBuildDir}/,$(subst /,__,$(subst ..,++,$(srcs:.cpp=.o))))
  cpp2d = $(addprefix ${msBuildDir}/,$(subst /,__,$(subst ..,++,$(srcs:.cpp=.d))))

  objs += $(cpp2o)
  deps += $(cpp2d)

msApp: psAppDirs $(objs)
	@echo Building ${CURDIR}  -> $(msBinDir)/${exec}
	@${msCXX}  $(objs) -o $(msBinDir)/${exec} ${msLFLAGS}

msLib: psAppDirs $(objs)
	@mkdir -p $(msLibDir)
	@echo  Building $(msLibDir)/${exec}
	@${msCXX} $(objs) -shared -o $(msLibDir)/lib${exec}.${SO} ${msLFLAGS}

.PHONY: clean ${deps}

clean:
	$(RM) $(objs) ${deps}

-include ${deps}


${msBuildDir}/%.Obj: $(OFObj2C)
	@echo  'Compiling $(OFObj2C)  *'
	@${msCXX}  ${msCFLAGS} ${OFCFLAGS} ${EXTRACFLAGS} -c $(OFObj2C) -o $@

${msBuildDir}/%.o: $(o2cpp)
	@echo  'Compiling $(o2cpp)   *'
	@${msCXX}  ${msCFLAGS}  ${EXTRACFLAGS} -c $(o2cpp) -o $@

# this is a note only, for how to use nmake in Windows, will not work with complex makefiles
# "c:\Program Files (x86)\Microsoft Visual Studio 12.\VC\bin\amd64_x86\vcvarsamd64_x86.bat"
# nmake
winVS:
	@cl -I..\libf2c /nologo /MT /EHsc /Ox  ${srcs} ..\..\bin\vcf2c.lib  /link -LARGEADDRESSAWARE /out:..\bin\gnflow_VS.exe
	@del *.obj

else
  msApp: ; $(error msApp target should be used togather with USE_msMAKE=1)
endif  #  USE_msMAKE  ###########################################################:





ifdef USE_msTEST #################### run tests #################################:
  # t_ is making targets .PHONY (re-run anyway)
  tst2test := $(addprefix T${msTestDir}/,$(subst /,__,$(subst ..,++,$(tsts))))
  test2tst = $(subst T${msTestDir}/,,$(subst __,/,$(subst ++,..,$@)))
  inp2app = $(lastword $(subst _, ,$(subst .sin,,$@)))

T${msTestDir}/%.mhd: $(test2tst)
	cp $(test2tst) ${msTestDir}/

T${msTestDir}/%.sin: $(test2tst)
	@echo detecting app from *_app.sin=="$@": $(inp2app)
	$(msSrc)/script/testApp "${msTestDir}"  $(inp2app) "${CURDIR}/$(test2tst)"  "${msRoot}"

T${msTestDir}/%.py: $(test2tst)
	echo python3 "${CURDIR}/$(test2tst)"
	$(msSrc)/script/testApp "${msTestDir}"  python3 "${CURDIR}/$(test2tst)"

T${msTestDir}/%.cpp: $(test2tst)
	echo ${msCXX}
	${msCXX} -std=c++11 $(test2tst) -o $@
	$(msSrc)/script/testApp "${msTestDir}"  "${CURDIR}/$@" "${CURDIR}/$(test2tst)"

T${msTestDir}/%.sh:
	$(msSrc)/script/testApp "${msTestDir}" "${CURDIR}/$(test2tst)"
#	(cd ${msTestDir} && $(test2tst))

test: msTstDirs $(tst2test) 
	@echo  All tests finished $(tst2test) ${msTestDir}/
 
.PHONY:  clean test 
endif  # USE_msTEST #################################################################:

